/**
 * 
 */
package org.paybiz.core.payplatform.aliPay.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.paybiz.constant.PayConstant;
import org.paybiz.core.payplatform.aliPay.constant.AlipayConstant;
import org.paybiz.core.payplatform.aliPay.util.AlipayBase;
import org.paybiz.core.service.pay.PayService;
import org.paybiz.crypto.Md5Encrypt;
import org.paybiz.model.PayModel;
import org.paybiz.model.PayReqResultDO;
import org.paybiz.util.DynamicConfig;
import org.paybiz.util.PaySignUtil;
import org.springframework.stereotype.Service;



/**
 * @Title: AliPayServiceImpl.java
 * @Description: 支付宝支付实现类
 * @author Nassir.wen
 * @date 2010-10-14 上午10:54:14
 * @version V1.0
 * @Company: MSD.
 * @Copyright Copyright (c) 2010
 */
@Service("aliPayService")
public class AliPayServiceImpl implements PayService {

	// 日志对象
	private static final Log logger = LogFactory.getLog(AliPayServiceImpl.class);
	// 内部密钥
	private static String msdValue = "";
	// 商户编号
	private static String ali_MerId = "";
	// 邮箱地址
	private static String ali_email = "";
	// 商户密钥
	private static String ali_keyValue = "";
	// 支付宝URL
	private static String ali_url = "";
	// 支付回调链接
	private static String ali_returnUrl = "";
	// 支付异步回调链接
	private static String ali_notifyUrl = "";
	// 支付宝查询链接
	private static String ali_queryUrl = "";

	public AliPayServiceImpl() {
		msdValue = DynamicConfig.getInstance().getValue(PayConstant.PAY_BIZ_KEY);
		ali_MerId = DynamicConfig.getInstance().getValue(AlipayConstant.ali_MerId);
		ali_email = DynamicConfig.getInstance().getValue(AlipayConstant.ali_email);
		ali_url = DynamicConfig.getInstance().getValue(AlipayConstant.ali_url);
		ali_keyValue = DynamicConfig.getInstance().getValue(
		        AlipayConstant.ali_keyValue);
		ali_returnUrl = DynamicConfig.getInstance().getValue(
		        AlipayConstant.ali_returnUrl);
		ali_notifyUrl = DynamicConfig.getInstance().getValue(
		        AlipayConstant.ali_notiftUrl);
		ali_queryUrl = DynamicConfig.getInstance().getValue(
		        AlipayConstant.ali_queryUrl);
	}

	@Override
	public PayReqResultDO pay(PayModel payDO) {
		PayReqResultDO resultDO = new PayReqResultDO();
		String service = "create_direct_pay_by_user"; // 快速付款交易服务
		String sign_type = "MD5"; // 文件加密机制
		String input_charset = "UTF-8"; // 编码类型

		Map<String, Object> params = new HashMap<String, Object>();
		// -------系统信息--------------------------
		params.put("service", service);
		params.put("partner", ali_MerId);
		params.put("show_url", ali_url); // 支付接口（不可以修改）
		params.put("seller_email", ali_email);
		params.put("_input_charset", input_charset); // 编码类型
		params.put("payment_type", "1"); // 支付宝类型.1代表商品购买（目前填写1即可，不可以修改）
		// -----商品信息
		params.put("out_trade_no", payDO.getOrderId()); // 商户网站订单（也就是外部订单号，是通过客户网站传给支付宝，不可以重复）
		params.put("subject", payDO.getSubject());
		params.put("body", payDO.getBody()); // 商品描述，推荐格式：商品名称（订单编号：订单编号）
		DecimalFormat df = new DecimalFormat("0.00");
		params.put("total_fee", df.format(((double) payDO.getPayMoney() / 100.0))); // 订单总价
		params.put("return_url", StringUtils.isNotEmpty(payDO.getSynCallbackUrl()) ? payDO.getSynCallbackUrl() : ali_returnUrl); // 支付完成后跳转返回的网址URL
		params.put("notify_url", StringUtils.isNotEmpty(payDO.getAsynCallbackUrl()) ? payDO.getAsynCallbackUrl() : ali_notifyUrl); // 通知接收URL(本地测试时，服务器返回无法测试)
		String Str=null;
		try {
			Str = URLEncoder.encode(payDO.getResultUrl(),"UTF-8");
		} catch (UnsupportedEncodingException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		params.put("extra_common_param",Str); // 商家数据包(自己定义)，原样返回。

		String prestr = "";
		prestr = prestr + ali_keyValue;
		String sign = Md5Encrypt.md5(getContent(params, ali_keyValue));
		StringBuffer payUrl = new StringBuffer();
		payUrl.append(ali_url);
		List keys = new ArrayList(params.keySet());
		for (int i = 0; i < keys.size(); i++) {
			try {
			    payUrl.append(keys.get(i)).append("=").append(URLEncoder.encode((String) params.get(keys.get(i)),
                                input_charset) + "&");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		payUrl.append("sign=").append(sign).append("&sign_type=").append(sign_type);
		keys.clear();
		keys = null;
		resultDO.setResult(0);
		resultDO.setPayUrl(payUrl.toString());
		resultDO.setHmac(PaySignUtil.getPayReqResultDOHmac(resultDO, msdValue));
		return resultDO;
	}

	/**
	 * 用于支付宝
	 * 
	 * @param params
	 * @param privateKey
	 * @return
	 */
	private String getContent(Map params, String privateKey) {
		List keys = new ArrayList(params.keySet());
		Collections.sort(keys);
		String prestr = "";
		for (int i = 0; i < keys.size(); i++) {
			String key = (String) keys.get(i);
			String value = (String) params.get(key);

			if (i == keys.size() - 1) {
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}
		return prestr + privateKey;
	}

	/**
	 * return -1 未支付   0  支付失败   1 支付成功  2异常情况 
	 */
	@Override
	public int autoCheckOrder(String orderId,Date date,Integer tag) {
		int isSuccess = -1;// 是否成功标识
		String service = "single_trade_query";// 支付宝查询服务--单笔查询服务
		String sign_type = "MD5";// 加密机制
		String input_charset = "UTF-8"; // 编码类型
		Map<String, String> params = new HashMap<String, String>();
		params.put("service", service);
		params.put("partner", ali_MerId);
		params.put("out_trade_no", orderId);
		params.put("_input_charset", input_charset);
		// 获取签名
		String sign = AlipayBase.buildMysign(params, ali_keyValue);
		String url = ali_queryUrl + "?";
		String parameter = "";
		parameter += AlipayBase.createLinkString_urlencode(params,
				input_charset);
		parameter = parameter + "sign=" + sign + "&sign_type=" + sign_type;
		url += parameter;
		if (logger.isInfoEnabled()) {
			logger.info("支付宝查询参数: " + params);
			logger.info("url:" + url);
		}
		SAXReader reader = new SAXReader();
		Document doc = null;
		try {
			doc = reader.read(new URL(url).openStream());
		} catch (MalformedURLException e) {
			e.printStackTrace();
			if (logger.isErrorEnabled()) {
				logger.error("支付宝查询出错,原因", e);
			}
			isSuccess = PayConstant.AUTO_CHECK_ORDER_ERROR;
		} catch (DocumentException e) {
			e.printStackTrace();
			if (logger.isErrorEnabled()) {
				logger.error("支付宝查询出错,原因", e);
			}
			isSuccess = PayConstant.AUTO_CHECK_ORDER_ERROR;
		} catch (IOException e) {
			e.printStackTrace();
			if (logger.isErrorEnabled()) {
				logger.error("支付宝查询出错,原因", e);
			}
			isSuccess = PayConstant.AUTO_CHECK_ORDER_ERROR;
		}
		if (doc == null) {
			if (logger.isInfoEnabled()) {
				logger.info("自动对账失败,支付宝请求查询失败");
			}
			//查询异常
			return isSuccess;
		}
		// 解析request列表下的信息
		List<Node> nodeList = doc.selectNodes("//alipay/*");
		// 判断是否成功
		for (Node node : nodeList) {
			// 支付状态 T为成功，F为失败
			if (node.getName().equals("is_success")
					&& node.getText().equals("T")) {
				List<Node> nodeTradeList = doc
						.selectNodes("//response/trade/*");
				Map<String, String> responseParams = new HashMap<String, String>();
				for (Node nodeResponse : nodeTradeList) {
					// 解析返回信息
					if (!"".equals(nodeResponse.getText())) {
						try {
							responseParams.put(nodeResponse.getName(),
									URLDecoder.decode(nodeResponse.getText(),
											"UTF-8"));
						} catch (UnsupportedEncodingException e) {
							e.printStackTrace();
						}
					}
				}
				if (logger.isInfoEnabled()) {
					logger.info("查询返回参数:" + responseParams);
				}
				// 返回数据签名
				String newSign = Md5Encrypt.md5(AlipayBase
						.createLinkString(responseParams)
						+ ali_keyValue);
				List<Node> nodeResponseList = doc.selectNodes("//sign");
				String responseSign = "";
				for (Node nodeSign : nodeResponseList) {
					responseSign = nodeSign.getText();
				}
				if (!newSign.equals(responseSign)) {
					if (logger.isInfoEnabled()) {
						logger.info("支付宝查询签名失败,支付宝签名:" + responseSign + "本地签名:"
								+ newSign);
					}
					//查询异常，签名错误
					return 2;
				}
				//判断是否支付成功
				String tradeStatus = responseParams.get(AlipayConstant.ALI_TRADE_STATUS);
				if(logger.isInfoEnabled()){
					logger.info("alipay trade status : " + tradeStatus);
				}
				if(StringUtils.equals(tradeStatus, AlipayConstant.ALI_TRADE_SUCCESS)){
					//支付成功
					isSuccess = PayConstant.RESULT_SUCCESS;
					if (logger.isInfoEnabled()) {
						logger.info("自动对账订单号:" + orderId + " 支付宝已支付成功!");
					}
				} else if(StringUtils.equals(tradeStatus, AlipayConstant.ALI_WAIT_BUYER_PAY)){
					//等待支付
					isSuccess = PayConstant.NOT_PAY;
					if (logger.isInfoEnabled()) {
						logger.info("自动对账订单号:" + orderId + " 支付宝等待支付!");
					}
				}else{
					isSuccess = PayConstant.NOT_PAY;
				}
				return isSuccess;
			}
		}
		if (isSuccess == 0) {
			if (logger.isInfoEnabled()) {
				String error = "自动对账，支付宝查询出错";
				for (Node nodeerror : nodeList) {
					if (nodeerror.getName().equals("error")) {
						String err = nodeerror.getText();
						if ("ILLEGAL_SIGN".equals(err)) {
							error += ",ILLEGAL_SIGN 签名不正确";
							isSuccess = 2;
						} else if ("ILLEGAL_ARGUMENT".equals(err)) {
							error += ",ILLEGAL_ARGUMENT 参数不正确";
							isSuccess = 2;
						} else if ("TRADE_NOT_EXIST".equals(err)) {
							error += ",TRADE_NOT_EXIST 交易不存在";
							isSuccess = -1;
						} else if ("ILLEGAL_PARTNER".equals(err)) {
							error += "ILLEGAL_ARGUMENT 合作伙伴不存在";
							isSuccess = 2;
						}
						break;
					}
				}
				logger.info(error);
				return isSuccess;
			}
		}
		return isSuccess;
	}

}
